////////////////////////////////////////////////
//	File	:	"CObjectManager.cpp"
//
//	Author	:	David Brown (DB)
//
//	Purpose	:	To contain and manage all of our game objects.
/////////////////////////////////////////////////
#include "../headers/StdAfx.h"

#include "../headers/ObjectManager.h"
#include "../Messaging/EventSystem.h"
#include "../headers/Base.h"
#include "../Systems/Direct3D.h"


CObjectManager * CObjectManager::instance;

CObjectManager::CObjectManager(void)
{
	instance = NULL;

	m_vObjectList[0] = vector<CBase *>();
	m_vObjectList[1] = vector<CBase *>();
	m_vObjectList[2] = vector<CBase *>();
	m_vObjectList[3] = vector<CBase *>();

	m_uiIDCounter = 1000;

}

CObjectManager::~CObjectManager(void)
{
}

void CObjectManager::UpdateObjects(float dt, bool getInput)
{

	//Here we only update objects in the main list
	for(unsigned int i = 0; i < 4; i++)
	{
		vector<CBase *> * vect = &m_vObjectList[i];
		vector<CBase*>::iterator iter = (*vect).begin();

		while(iter != (*vect).end())
		{
			if((*iter) != NULL)
			{
				(*iter)->Update(dt, getInput);
			}
			else
			{
				COUT("NULL object in OM\n");
			}
			iter++;

		}
	}
}

void CObjectManager::RenderObjects(vector2D vCamera)
{
	CDirect3D::GetInstance()->SpriteEnd();
	for(unsigned int j = 0; j < 3; j++)
	{
		unsigned int size = (unsigned int)m_vObjectList[j].size();
		CDirect3D::GetInstance()->SpriteBegin();
		vector<CBase *> * vect = &m_vObjectList[j];
		for (unsigned int i=0; i < size; i++)
		{
			//if(m_vObjectList[j][i]->GetPosX() - fCameraX < 1000 && m_vObjectList[j][i]->GetPosX() - fCameraX > -1000)
			(*vect)[i]->Render(vCamera);
		}
		CDirect3D::GetInstance()->SpriteEnd();
	}
	CDirect3D::GetInstance()->SpriteBegin();
}

void CObjectManager::AddObject(CBase* pObject, unsigned int nLayer)
{
	//	Check for valid object pointer
	if (pObject == NULL)
		return;

	//give new objects a unique id
	if(pObject->GetID() == 0)
	{
		pObject->SetID(m_uiIDCounter++);
	}

	//	Add object to object list
	m_vObjectList[nLayer].push_back(pObject);
	pObject->AddRef();

	// Add to collidable object list
	if(pObject->GetCanCollide())
	{
		m_vCollidableObjectList.push_back(pObject);
		pObject->AddRef();
	}

	// Add to obstacle list
	if(pObject->GetIsObstacle())
	{
		m_vObstacleList.push_back(pObject);
		pObject->AddRef();
	}

	// Add to object by type list
	m_vObjectByType[pObject->GetType()].push_back(pObject);
	pObject->AddRef();

	//	Add my reference to it.

}

void CObjectManager::RemoveObject(CBase* pObject, unsigned int nLayer)
{
	//	Check for valid object pointer
	if (pObject == NULL)
		return;

	bool collidable = pObject->GetCanCollide(); //need to capture here, otherwise might get Released and can't check afterwards
	bool obstacle = pObject->GetIsObstacle();

	vector<CBase*> * vect = &m_vObjectList[nLayer];
	for (vector<CBase*>::iterator iter = vect->begin();
		iter != vect->end();
		iter++)
	{
		// if this is the object we are looking for.
		if ((*iter) == pObject)
		{
			// Remove my reference to this object.
			(*iter)->Release();

			// Remove the object from the list
			iter = vect->erase(iter);

			break;
		}
	}

	vect = &m_vObjectByType[pObject->GetType()];
	for (vector<CBase*>::iterator iter = vect->begin();
		iter != vect->end();
		iter++)
	{
		// if this is the object we are looking for.
		if ((*iter) == pObject)
		{
			// Remove my reference to this object.
			(*iter)->Release();

			// Remove the object from the list
			vect->erase(iter);

			break;
		}
	}

	if(collidable)
	{
		for (vector<CBase*>::iterator iter = m_vCollidableObjectList.begin();
			iter != m_vCollidableObjectList.end();
			iter++)
		{
			// if this is the object we are looking for.
			if ((*iter) == pObject)
			{
				// Remove my reference to this object.
				(*iter)->Release();

				// Remove the object from the list
				iter = m_vCollidableObjectList.erase(iter);

				break;
			}
		}
	}

	if(obstacle)
	{
		for (vector<CBase*>::iterator iter = m_vObstacleList.begin();
			iter != m_vObstacleList.end();
			iter++)
		{
			// if this is the object we are looking for.
			if ((*iter) == pObject)
			{
				// Remove my reference to this object.
				(*iter)->Release();

				// Remove the object from the list
				iter = m_vObstacleList.erase(iter);

				break;
			}
		}
	}
}

void CObjectManager::RemoveAllObjects(void)
{
	//	Call Release() on all objects.
	for(unsigned int j = 0; j < 4; j++)
	{
		vector<CBase*> * vect = &m_vObjectList[j];
		for (unsigned int i=0; i < vect->size(); i++)
		{
			(*vect)[i]->Release();
		}

		//	Collapse the vector
		vect->clear();
	}


	for (unsigned int i=0; i < m_vCollidableObjectList.size(); i++)
	{
		m_vCollidableObjectList[i]->Release();
	}

	for (unsigned int i=0; i < m_vObstacleList.size(); i++)
	{
		m_vObstacleList[i]->Release();
	}

	//	Collapse the vector
	m_vCollidableObjectList.clear();
	m_vObstacleList.clear();

	for(unsigned int j = 0; j < OBJ_END; j++)
	{
		vector<CBase*> * vect = &m_vObjectByType[j];

		for (unsigned int i=0; i < vect->size(); i++)
		{
			(*vect)[i]->Release();
		}
		//	Collapse the vector
		vect->clear();
	}

}


CObjectManager * CObjectManager::GetInstance()
{
	if(instance == NULL)
	{
		instance = new CObjectManager();
	}

	return instance;
}

void	CObjectManager::DeleteInstance()
{
	if(instance)
	{
		delete instance;
		instance = NULL;
	}
}

void CObjectManager::CheckCollision()
{
	vector<CBase *>*  vect = &m_vObjectList[2];
	int size = (int)m_vCollidableObjectList.size();
	int size1 = (int)m_vObjectList[2].size();

	//only check for collisions between things in the colliableObjectList and everyone else
	//this is a hack optimization

	for(int i = 0 ;i < size; i++)
	{	
		for(int j = 0;j < size1; j++)
		{
			//if(i != j)
			//{
			//Only check for collisions on players layer, layer 2
			CBase * obj1 = m_vCollidableObjectList[i];
			CBase * obj2 = (*vect)[j];
			if(obj1->GetType() != obj2->GetType())
			{
				if(obj1->CheckCollision(obj2))
				{
					//CEventSystem::GetInstance()->SendEvent("collision", 0.0f, obj2);						
				}
			}
			//}
		}
	}


}

CBase * CObjectManager::GetObjectById(unsigned int id)
{
	vector<CBase *> * vect = &(m_vObjectList[2]);
	unsigned int size = (unsigned int)(*vect).size();

	for(unsigned int i = 0 ;i < size; i++)
	{	
		if((*vect)[i]->GetID() == id)
		{
			return (*vect)[i];
		}

		//if(i > id) //id's should be stored in order
		//	return NULL;
	}

	return NULL;
}
